/**
 *    Copyright (C) 2008  Victor Smirnov <aist11@gmail.com>
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License along
 *    with this program; if not, write to the Free Software Foundation, Inc.,
 *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 *    See LICENSE.exceptions in the root folder of this project for possible
 *    exceptions
 *
 */


#include <cubefs/api/api.hpp>
#include <iostream>
#include <bm_tools.h>

#include <vector>
#include <algorithm>

using namespace cubefs;
using namespace cubefs::api;
using namespace cubefs::core;

using namespace std;

const Int SIZE = 1000;

const BigInt MAX_VALUE = 0x7fffffffffffffff;

struct KVPair {
    BigInt key_, value_;
    
    KVPair(BigInt key, BigInt value): key_(key), value_(value) {}
    
    KVPair(){}
};

typedef vector<KVPair> PairVector;

bool KVPairSortPredicate(const KVPair& d1, const KVPair& d2)
{
  return d1.key_ < d2.key_;
}

void sort(PairVector& v) {
    std::sort(v.begin(), v.end(), KVPairSortPredicate);
}

void checkIterator(TreeMap* map, TreeMap::Pair* pair, PairVector& pairs) {
	TreeMapIterator* iter = (TreeMapIterator*) map->CreateIterator();
	StaticListOfTyped* keys = TypedCast<StaticListOfTyped>(pair->key());        
        Int idx0 = pair->GetIdx();
        Number* key   = TypedCast<Number>(keys->Get(idx0));
	Number* value = TypedCast<Number>(pair->value());

	Int idx = 0;
	while (!iter->IsFlag(Iterator::ITER_EOF)) {
	    iter->GetValue(pair);
	    
	    if (pairs[idx].key_ != key->GetBigIntValue()) cout<<"key "<<idx<<endl;
	    if (pairs[idx].value_ != value->GetBigIntValue()) cout<<"value "<<idx<<endl;
	    
	    iter->Next();
	    idx++;
	}
	
	if (idx != pairs.size()) cout<<"iterator.size "<<idx<<" "<<pairs.size()<<endl;
}


int main(int argc, char** argv, const char **envp) {
	try {
		InitTypeSystem(envp);

		Container* container = Container::Create("Generic", "0.0.0", Container::CONTAINER);
		Manager* manager = static_cast<Manager*>(Container::Create("Stream", "0.0.0", Container::PAGE_MANAGER));

		container->SetManager(manager);
		container->GetManager()->GetLogger()->SetLogLevel(LogHandler::ERROR);


		PairVector pairs;
		PairVector pairs_sorted;

		for (Int c = 0; c < SIZE; c++)
		{
			pairs.push_back(KVPair(get_random(MAX_VALUE), get_random(MAX_VALUE)));
		}

		TreeMap* map = (TreeMap*) container->CreateCollection(2, 1);

		map->SetMaxChildrenPerNode(5);

		TreeMap::Pair* pair   =  map->CreatePairHolder();
		StaticListOfTyped* keys = TypedCast<StaticListOfTyped>(pair->key());

		Int idx0 = pair->GetIdx();

		Number* key    = TypedCast<Number>(keys->Get(idx0));
		Number* value  = TypedCast<Number>(pair->value());

		for (int c = 0; c < SIZE; c++)
		{
			key->SetBigIntValue(pairs[c].key_);
			value->SetBigIntValue(pairs[c].value_);
			map->Put(pair);

			map->GetSize();
			container->Check();

			pairs_sorted.push_back(pairs[c]);
			sort(pairs_sorted);

			checkIterator(map, pair, pairs_sorted);
		}

		for (int c = 0; c < SIZE; c++)
		{
			key->SetBigIntValue(pairs[c].key_);
			((Map*)map)->Get(pair);

			if (pairs[c].value_ != value->GetBigIntValue()) {
				cout<<"query "<<c<<endl;
			}
		}

		for (int c = 0; c < SIZE; c++)
		{
			key->SetBigIntValue(pairs[c].key_);
			map->Remove(pair);

			BigInt size = SIZE - c - 1;
			if (size != map->GetSize()) cout<<"Remove.size "<<c<<" "<<map->GetSize()<<endl;
			container->Check();

			Int idx = -1;
			for (int x = 0; x < pairs_sorted.size(); x++) {
				if (pairs_sorted[x].key_ == pairs[c].key_) {
					pairs_sorted.erase(pairs_sorted.begin() + x);
					//cout<<"remove "<<x<<endl;
				}
			}

			checkIterator(map, pair, pairs_sorted);
		}

		delete container;
	}
	catch (CubefsException ex) {
		cout<<"TypeCastException "<<ex.source()<<" "<<ex.message()<<endl;
	}
}
